package sale

import (
	"fmt"
	"time"
	"errors"
	"strconv"
	"strings"
	"encoding/json"
	"dhfshop/models/sale"
	"dhfshop/utils/uuid"
	"dhfshop/service/nsqcli"
	"dhfshop/utils/helper"
	"github.com/astaxie/beego"
	"dhfshop/controllers/base"
	"github.com/astaxie/beego/validation"
)

// 卖家商品管理
type ItemController struct {
	base.BaseController
}


func (this *ItemController) PubItemsList() {
	query,subquery,fields,order_by,offset,limit,err := this.GetQueryPara()
	if err != nil {
	   this.ServeError(err.Error())
	   return
	}
	itemIdArr := []string{}
	if len(subquery) > 0 {
	    idArr, err := sale.GetItemIdArrBySubQuery(subquery)
	    if len(idArr) > 0 && err == nil {
	        itemIdArr = idArr
	    }
	}
	var allowStoreId []int64
	if this.CurrentUser != nil {
	    allowStoreId = this.CurrentUser.AllowStoreId
	}
	//beego.Debug("allowStoreId:", allowStoreId)
	l, cnt, err := sale.GetAllItems(allowStoreId,query,itemIdArr,fields,order_by,offset,limit)
	if err != nil {
	    this.ServeError(err.Error())
		return
	}
	r := struct {
		TotalCount   int64           `json:"total_count"`
		Items        []*sale.Item  `json:"items"`
	}{TotalCount: cnt, Items: l}
	this.Data["json"] = r
	this.ServeJSON()
}

func (this *ItemController) ItemsList() {
	query,subquery,fields,order_by,offset,limit,err := this.GetQueryPara()
	if err != nil {
	   this.ServeError(err.Error())
	   return
	}
	partnerId := int64(this.Ctx.Input.GetData("curCompanyId").(int))
	query["partner_id"] = strconv.FormatInt(partnerId, 10)
	itemIdArr := []string{}
	if len(subquery) > 0 {
	    idArr, err := sale.GetItemIdArrBySubQuery(subquery)
	    if len(idArr) > 0 && err == nil {
	        itemIdArr = idArr
	    }
	}
	//根据pickpoint_id过滤查询
	if _, ok := query["pickpoint_id"]; ok {      
		idArr, err := sale.GetItemIdsByPickpointId(query["pickpoint_id"])
	    if len(idArr) > 0 && err == nil {
	        itemIdArr = idArr
	    }	
	}
	var allowStoreId []int64
	if this.CurrentUser != nil {
	    allowStoreId = this.CurrentUser.AllowStoreId
	}
	//beego.Debug("allowStoreId:", allowStoreId)
	l, cnt, err := sale.GetAllItems(allowStoreId,query,itemIdArr,fields,order_by,offset,limit)
	if err != nil {
	    this.ServeError(err.Error())
		return
	}
	rsp := struct {
		TotalCount   int64         `json:"total_count"`
		Items        []*sale.Item  `json:"items"`
	}{TotalCount: cnt, Items: l}
	this.Data["json"] = rsp
	this.ServeJSON()
}

func (this *ItemController) OpenStocksGet() {
	//curRoleId := this.Ctx.Input.GetData("curRoleId").(int) 
	companyId := int64(this.Ctx.Input.GetData("curCompanyId").(int))
	curUserId := int64(this.Ctx.Input.GetData("curUserId").(int))
	if curUserId == 0 {
		this.ServeError("user is not login")
	    return
	}
	offset := 0             //default is 0
	limit := 10             //default is 50
	v := struct {
	    StoreId       int64      `form:"store_id"`
		ItemId        string     `form:"item_id"`
		StartCreated  string     `form:"start_created"` 
		EndCreated    string     `form:"end_created"`
		PageSize      int        `form:"page_size"`
		PageNo        int        `form:"page_no"`
	}{PageSize:10, PageNo:1}     
	this.ParseForm(&v)
	valid := validation.Validation{}
	valid.Range(v.PageSize,1,1000,"page_size")
	valid.Range(v.PageNo,1,1000,"page_no")
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key+" "+valid.Errors[0].Message)
		return 
	}
	v.PageNo = v.PageNo - 1     //为了计算offset
	offset = v.PageNo*v.PageSize
	limit = v.PageSize
	l, cnt, err := sale.GetOpenApiStocks(companyId,v.StoreId,v.ItemId,v.StartCreated,v.EndCreated,offset,limit)
	if err != nil {
	    this.ServeError(err.Error())
		return	
	}
	r := struct {
	    TotalCount int64        `json:"total_count"`
	    Items      []*sale.Item `json:"item_stock"`
	}{TotalCount: cnt, Items: l}
	this.Data["json"] = r
	this.ServeJSON()
}

func (this *ItemController) OpenStocksPut() {
	//curRoleId := this.Ctx.Input.GetData("curRoleId").(int) 
	//companyId := int64(this.Ctx.Input.GetData("curCompanyId").(int))
	curUserId := int64(this.Ctx.Input.GetData("curUserId").(int))
	if curUserId == 0 {
		this.ServeError("user is not login")
	    return
	}
	v := struct {
	    StoreId    int64   `form:"store_id"`
		//ItemId     string  `form:"item_id"`
		//OuterId    string  `form:"outer_id"` 
		SkuId      string  `form:"sku_id"`
		Barcode    string  `form:"barcode"`
		SkuOuterId string  `form:"sku_outer_id"`
		SkuStocks  int32   `form:"sku_stocks"`
	}{}
	this.ParseForm(&v)
	valid := validation.Validation{}
	valid.Range(v.SkuStocks,1,10000,"sku_stocks")
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key+" "+valid.Errors[0].Message)
		return 
	}
	skuId , err := strconv.ParseInt(v.SkuId, 10, 64)
    sku, err := sale.GetSkuByMulti(skuId, v.SkuOuterId, v.Barcode)
	if err != nil {
	    this.ServeError(err.Error())
		return
	}
	sku.SkuStocks = v.SkuStocks
	if err = sale.UpdateSkuBySkuId(sku, "sku_stocks"); err != nil {
	    this.ServeError(err.Error())
		return
	}
	item, err := sale.GetItemByItemId(sku.Item.ItemId)
	if err != nil {
	    this.ServeError(err.Error())
		return
	}
	this.Data["json"] = item
	this.ServeJSON()
}

func (this *ItemController) Post() {
	var v sale.Item
	this.ParseForm(&v)
	valid := validation.Validation{}
	//valid.Required(v.CategoryId, "category_id")
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key+" "+valid.Errors[0].Message)
		return
	}
	v.PartnerId = int64(this.Ctx.Input.GetData("curCompanyId").(int))
	saleNsqMsg := struct {
		PartnerId int64   `json:"partner_id"`        
		StoreId   int64   `json:"store_id"`       
		ItemId    int64   `json:"item_id"`        
		Type      string  `json:"type"`     
		TimeAt    string  `json:"time_at"`
	}{PartnerId:v.PartnerId,StoreId:v.StoreId}
	saleNsqMsg.TimeAt = time.Now().UTC().Format("200601021504")
	//
	if len(v.ItemIdStr) == 0 {    //add item
	    v.StatusId = 1
		v.ItemId, _ = uuid.GetSnowFlakeId(uuid.Worker)
		if v.OnShelves == 0 {
		    if msgBody, err := json.Marshal(v); err == nil {
				beego.Emergency("add on_shelves is 0", string(msgBody))
			}
		}
		if len(v.SkuJson) > 3 {
			//beego.Debug("v.SkuJson:", v.SkuJson)
			err := json.Unmarshal([]byte(v.SkuJson), &v)
			if err != nil {
				this.ServeError(err.Error())
				return
			}
			for _, sku := range v.Skus {
				sku.PartnerId = v.PartnerId
				sku.SkuId, _ = uuid.GetSnowFlakeId(uuid.Worker)
				sku.Item = &v               // pay more attention
				sku.StatusId = 1
			}
			_, err = sale.AddItem(&v)
			if err != nil {
				this.ServeError(err.Error())
				return 
			}
			if err := sale.AddMultiSkus(v.Skus); err != nil {
				this.ServeError(err.Error())
				return
			}
		}else{
		    _, err := sale.AddItem(&v)
			if err != nil {
				this.ServeError(err.Error())
				return 
			}
		}
		saleNsqMsg.Type = "insert"
	}else{   //add sku
	    if v.StoreId == 0 {
		   this.ServeError("创建sku,店铺id为零")
		   return
		}
		itemId, err := strconv.ParseInt(v.ItemIdStr, 10, 64)
		v.ItemId = itemId
		if err != nil {
			this.ServeError(err.Error())
			return
		}
	    oldItem, err := sale.GetItemByItemId(itemId)
		if err != nil {
			this.ServeError(err.Error())
			return
		}
		if len(v.SkuJson) > 0 {
			err := json.Unmarshal([]byte(v.SkuJson), &v)
			if err != nil {
				this.ServeError(err.Error())
				return
			}
			for _, sku := range v.Skus {
				sku.PartnerId = oldItem.PartnerId
				sku.SkuId, _ = uuid.GetSnowFlakeId(uuid.Worker)
				sku.Item = oldItem               // pay more attention
				sku.StatusId = 1
			}
			if err := sale.AddMultiSkus(v.Skus); err != nil {
				this.ServeError(err.Error())
				return
			}
		}
		item := new(sale.Item)
		item.ItemId = itemId
		item.StockNum = sale.GetOnSaleSkuStockNum(itemId, 1)
		if err := sale.UpdateItemByItemId(item, "stock_num"); err != nil {
	        this.ServeError(err.Error())
			return
	    }
		saleNsqMsg.Type = "update"
	}
	v.ItemIdStr = fmt.Sprintf("%d", v.ItemId)
	saleNsqMsg.ItemId = v.ItemId
	saleJson, err := json.Marshal(&saleNsqMsg)
	if err != nil {
		beego.Debug(err.Error())
		return
	}
	address := beego.AppConfig.String("NsqUrl")
	topic := "itemModifyNotify"
	if err = nsqcli.StartProducer(address, topic, saleJson); err != nil {
		beego.Debug("StartProducer err:", err.Error())
	}
	//
	rsp := struct {
		ItemId    string       `json:"item_id"`
	    Created   time.Time    `json:"created"`
	}{ItemId: v.ItemIdStr, Created:time.Now().UTC()}
	this.Data["json"] = rsp
	this.ServeJSON()
}

func (this *ItemController) Put() {
	v := sale.Item{}
	this.ParseForm(&v)  
	valid := validation.Validation{}
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key+" "+valid.Errors[0].Message)
		return 
	}
	var err error
	v.ItemId, err = strconv.ParseInt(v.ItemIdStr, 10, 64)
	if err != nil {
	    this.ServeError(err.Error())
		return
	}
	if !this.CurrentUser.Admin {
	    var allowStoreId []int64
		if this.CurrentUser != nil {
			allowStoreId = this.CurrentUser.AllowStoreId
		}
		beego.Debug("item put,allowstoreid:",allowStoreId,"store_id:",v.StoreId)
		if _, err := helper.Contains(v.StoreId, allowStoreId); err != nil {
		   this.ServeError("权限不足,请配置相关权限")
		   beego.Debug("error:", err.Error())
		   return
		}
	}
	oldItem, err := sale.GetItemByItemId(v.ItemId)
	if err != nil {
	    this.ServeError(err.Error())
		return
	}
	excludeArr := []string{"skus,p_item_id"}
	updateFields, err := this.GetUpdateFields(v, "", "form", excludeArr)
	if err != nil {
	   this.ServeError(err.Error())
		return
	}
	if v.OnShelves == 0 {
		if msgBody, err := json.Marshal(v); err == nil {
			beego.Emergency("update on_shelves is 0", string(msgBody))
		}
	}
	if len(v.PItemIdStr) > 0 {
		v.PItemId, _= strconv.ParseInt(v.PItemIdStr, 10, 64)
	}
	if err := sale.UpdateItemByItemId(&v, updateFields...); err != nil{
		this.ServeError(err.Error())
		return
	}
	if len(v.SkuJson) > 0 {
	    arrJson, err := helper.SplitJsonArr(v.SkuJson)
		if err != nil {
			this.ServeError(err.Error())
		    return
		}
		for _, str := range arrJson {
			var reqSku sale.Sku
			if err = json.Unmarshal([]byte(str), &reqSku); err != nil {
				this.ServeError(err.Error())
		        return
			}
			if len(reqSku.SkuIdStr) < 3 {
			    continue
			}
			reqSku.Item = &v               // pay more attention
			reqSku.SkuId, err = strconv.ParseInt(reqSku.SkuIdStr, 10, 64)
			if err != nil {
				this.ServeError(err.Error())
				return
			}
			if _, err := sale.GetSkuBySkuId(reqSku.SkuId); err == nil{
				updateField, err := this.GetUpdateFields(reqSku, str, "json", []string{""})
				if err != nil {
					this.ServeError(err.Error())
					return
				}
			    if err := sale.UpdateSkuBySkuId(&reqSku, updateField...); err != nil {
		            this.ServeError(err.Error())
                    return 			
	            }
			}
	    }
        item := new(sale.Item)
		item.ItemId = v.ItemId
		item.StockNum = sale.GetOnSaleSkuStockNum(v.ItemId, 1)
		if err := sale.UpdateItemByItemId(item, "stock_num"); err != nil {
	        this.ServeError(err.Error())
			return
	    }		
	}
	saleNsqMsg := struct {
		PartnerId int64   `json:"partner_id"`        
		StoreId   int64   `json:"store_id"`       
		ItemId    int64   `json:"item_id"`        
		Type      string  `json:"type"`     
		TimeAt    string  `json:"time_at"`
	}{PartnerId:oldItem.PartnerId,StoreId:oldItem.StoreId,ItemId:v.ItemId,Type:"update"}
	saleNsqMsg.TimeAt = time.Now().UTC().Format("200601021504")
	saleJson, err := json.Marshal(&saleNsqMsg)
	if err != nil {
		beego.Debug(err.Error())
		return
	}
	address := beego.AppConfig.String("NsqUrl")
	topic := "itemModifyNotify"
	if err = nsqcli.StartProducer(address, topic, saleJson); err != nil {
		beego.Debug("StartProducer err:", err.Error())
	}
	//
	rsp := struct {
		    ItemId    string      `json:"item_id"`
	        Modified  time.Time   `json:"modified"`
	    }{ItemId:v.ItemIdStr, Modified:time.Now().UTC()}
	this.Data["json"] = rsp
	this.ServeJSON()
}
// 删除item和skus
func (this *ItemController) Delete() {
    companyId := int64(this.Ctx.Input.GetData("curCompanyId").(int))
    //curUserId := this.Ctx.Input.GetData("curUserId").(int)
	v := struct {
		CompanyId  int64     `form:"-"  valid:"Required;Min(1)"`
	    ItemId     string  `form:"item_id" valid:"Required"`
		SkuId      string  `form:"sku_id"`
	}{CompanyId: companyId} 
	this.ParseForm(&v)
	valid := validation.Validation{}
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key+" "+valid.Errors[0].Message)
		return
	}
	if len(v.SkuId) > 0 {
	    itemId, err := strconv.ParseInt(v.ItemId, 10, 64)
		if err != nil {
			this.ServeError(err.Error())
			return
		}
		skuId, err := strconv.ParseInt(v.SkuId, 10, 64)
		if err != nil {
			this.ServeError(err.Error())
			return
		}
		if err := sale.DeleteSkuBySkuId(skuId); err != nil {
	        this.ServeError(err.Error())
			return
	    }
		item := new(sale.Item)
		item.ItemId = itemId
		item.StockNum = sale.GetOnSaleSkuStockNum(itemId, 1)
		if err := sale.UpdateItemByItemId(item, "stock_num"); err != nil {
	        this.ServeError(err.Error())
			return
	    }
	}else{
	    itemId, err := strconv.ParseInt(v.ItemId, 10, 64)
		if err != nil {
			this.ServeError(err.Error())
			return
		}
        if err := sale.DeleteItemByItemId(itemId); err != nil {
	        this.ServeError(err.Error())
			return
	    }
	}
	rsp := struct {
		ItemId     string      `json:"item_id"`
		Modified   time.Time   `json:"modified"`
	}{ItemId:v.ItemId, Modified:time.Now().UTC()}
	this.Data["json"] = rsp
	this.ServeJSON()
}

func (this *ItemController) StatusPut() {
	companyId := int64(this.Ctx.Input.GetData("curCompanyId").(int))
    //curUserId := this.Ctx.Input.GetData("curUserId").(int)
	v := struct {
		CompanyId  int64   `form:"-"  valid:"Required;Min(1)"`
	    ItemId     string  `form:"item_id" valid:"Required"`
		SkuId      string  `form:"sku_id"`
		StatusId   int32   `form:"status_id" valid:"Required"`
	}{CompanyId: companyId} 
	this.ParseForm(&v)
	valid := validation.Validation{}
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key+" "+valid.Errors[0].Message)
		return
	}
	if len(v.SkuId) > 0 {
	    itemId, err := strconv.ParseInt(v.ItemId, 10, 64)
		if err != nil {
			this.ServeError(err.Error())
			return
		}
		skuId, err := strconv.ParseInt(v.SkuId, 10, 64)
		if err != nil {
			this.ServeError(err.Error())
			return
		}
		m := new(sale.Sku)
		m.SkuId = skuId
		m.StatusId = v.StatusId
		if err := sale.UpdateSkuBySkuId(m, "status_id"); err != nil {
	        this.ServeError(err.Error())
			return
	    }
		item := new(sale.Item)
		item.ItemId = itemId
		item.StockNum = sale.GetOnSaleSkuStockNum(itemId, 1)
		if err := sale.UpdateItemByItemId(item, "stock_num"); err != nil {
	        this.ServeError(err.Error())
			return
	    }
	}else{
	    itemId, err := strconv.ParseInt(v.ItemId, 10, 64)
		if err != nil {
			this.ServeError(err.Error())
			return
		}
        m := new(sale.Item)
		m.ItemId = itemId
		m.StatusId = v.StatusId
		if err := sale.UpdateItemByItemId(m, "status_id"); err != nil {
	        this.ServeError(err.Error())
			return
	    }
	}
	rsp := struct {
	    ItemId    string      `json:"item_id"`
	    Modified  time.Time   `json:"modified"`
	}{ItemId:v.ItemId, Modified:time.Now().UTC()}
	this.Data["json"] = rsp
	this.ServeJSON() 
}

func (this *ItemController) GetStockPara()(map[string]string,[]string,map[string]string,int,int,error) {
	query := make(map[string]string)
	fields := []string{"item_id","title","outer_id","barcode","stock_num"}
	orderBy := make(map[string]string)
	offset := 0     //default is 0
	limit := 10    //default is 10
	v := struct {
		ItemId       string  `json:"item_id"`       
		Title        string  `json:"title"`       
	    OuterId      string  `json:"outer_id"`     
		Barcode      string  `json:"barcode"` 
		StartCreated string  `json:"start_created"`  
		EndCreated   string  `json:"end_created"`
		OrderBy      string  `json:"order_by"`
		PageSize     int     `json:"page_size"`
		PageNo       int     `json:"page_no"`
	}{PageSize:10, PageNo:1}
	//
	reqBody := this.Ctx.Input.RequestBody
	if len(reqBody) > 0 {
	    if err := json.Unmarshal(reqBody, &v); err != nil {
		   return query,fields,orderBy,offset,limit,err
	    }
	}
	v.PageNo = v.PageNo - 1     //为了计算offset
    if len(v.ItemId) > 0 {
	    query["item_id"] = v.ItemId
	}
    if len(v.Title) > 0 {
	    query["title"] = v.Title
	}
	if len(v.OuterId) > 0 {
	    query["outer_id"] = v.OuterId
	}
	if len(v.Barcode) > 0 {
	    query["barcode"] = v.Barcode
	}
	if len(v.StartCreated) > 0 {
	    query["start_created"] = v.StartCreated
	}
	if len(v.EndCreated) > 0 {
	    query["end_created"] = v.EndCreated
	}
    if len(v.OrderBy) > 2 {
	    for _, cond := range strings.Split(v.OrderBy, ",") {
	        kv := strings.Split(cond, ":")
	        if len(kv) != 2 {
	            err := errors.New("Error: invalid order_by key/value pair")
	            return query,fields,orderBy,offset,limit,err
	        }
	        k, v := kv[0], kv[1]
	        orderBy[k] = v
	    }
	}
	offset = v.PageNo*v.PageSize
	limit = v.PageSize
	return query,fields,orderBy,offset,limit,nil
}

func (this *ItemController) ItemsStockList() {
	query,fields,order_by,offset,limit,err := this.GetStockPara()
	if err != nil {
	   this.ServeError(err.Error())
	   return
	}
	partnerId := int64(this.Ctx.Input.GetData("curCompanyId").(int))
	query["partner_id"] = strconv.FormatInt(partnerId, 10)
	itemIdArr := []string{}
	var allowStoreId []int64
	list, cnt, err := sale.GetAllItems(allowStoreId,query,itemIdArr,fields,order_by,offset,limit)
	if err != nil {
	    this.ServeError(err.Error())
		return
	}
	rsp := struct {
		TotalCount   int64         `json:"total_count"`
		Items        []*sale.Item  `json:"items"`
	}{TotalCount: cnt, Items: list}
	this.Data["json"] = rsp
	this.ServeJSON()
}

func (this *ItemController) StockPut() {
	var v sale.Item
	reqBody := this.Ctx.Input.RequestBody
	if len(reqBody) > 0 {
	    if err := json.Unmarshal(reqBody, &v); err != nil {
		    this.ServeError(err.Error())
			return
	    }
	}
	v.PartnerId = int64(this.Ctx.Input.GetData("curCompanyId").(int))
	var itemId int64 = 0
	if len(v.ItemIdStr) > 0 {
	    itemId, _= strconv.ParseInt(v.ItemIdStr, 10, 64)
	}
	item, err := sale.GetItemByMulti(itemId, v.OuterId, v.Barcode)
	if err == nil {
	    item.StockNum = v.StockNum
		if err = sale.UpdateItemByItemId(item, "stock_num"); err != nil {
		    beego.Debug(err.Error())
			this.ServeError(err.Error())
		    return
		}
	}
	if len(v.Skus) > 0 {
		for _, sku := range v.Skus {
			var skuId int64 = 0
			if len(sku.SkuIdStr) > 0 {
				skuId, _= strconv.ParseInt(sku.SkuIdStr, 10, 64)
			}
			if m, err := sale.GetSkuByMulti(skuId,sku.SkuOuterId,sku.Barcode); err == nil {
			    m.SkuStocks = sku.SkuStocks
				if err = sale.UpdateSkuBySkuId(m, "sku_stocks"); err != nil {
				   beego.Debug(err.Error())
				}
			}           
		}
	}
	rsp := struct {
		ItemId   int64     `json:"item_id"`
	    Modified time.Time `json:"modified"`
	}{ItemId: item.ItemId, Modified:time.Now().UTC()}
	this.Data["json"] = rsp
	this.ServeJSON()
}
